package cn.iocoder.yudao.module.bk.util;

import cn.iocoder.yudao.framework.common.exception.ServiceException;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * 条纹码识别
 *
 * @author Administrator
 */
public class BarcodeReader {


    /**
     * 从图片地址读取条形码内容
     *
     * @param imageUrl 图片地址
     * @return 条形码内容
     * @throws IOException       如果图片读取失败
     * @throws NotFoundException 如果未找到条形码
     */
    public static String readBarcodeFromUrl(String imageUrl) throws IOException, NotFoundException {
        URL url = new URL(imageUrl);
        BufferedImage bufferedImage = ImageIO.read(url);
        LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result = new MultiFormatReader().decode(bitmap);
        return result.getText();
    }

    /**
     * 从MultipartFile文件读取条形码内容
     *
     * @param file MultipartFile文件
     * @return 条形码内容
     * @throws IOException       如果文件读取失败
     * @throws NotFoundException 如果未找到条形码
     */
    public static String readBarcodeFromMuFile(MultipartFile file) throws IOException, NotFoundException {
        InputStream inputStream = file.getInputStream();
        BufferedImage bufferedImage = ImageIO.read(inputStream);

        // 增强图像预处理：灰度化和二值化
        BufferedImage grayImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = grayImage.createGraphics();
        g.drawImage(bufferedImage, 0, 0, null);
        g.dispose();

        // 使用二值化处理
        BufferedImage binaryImage = new BufferedImage(grayImage.getWidth(), grayImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
        g = binaryImage.createGraphics();
        g.drawImage(grayImage, 0, 0, null);
        g.dispose();

        // 将预处理后的图片转换为LuminanceSource
        LuminanceSource source = new BufferedImageLuminanceSource(binaryImage);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

        // 尝试识别条形码
        try {
            Result result = new MultiFormatReader().decode(bitmap);
            if (result.getBarcodeFormat() == BarcodeFormat.EAN_13) {
                return result.getText();
            }
        } catch (NotFoundException ignored) {
            // 忽略单个块的识别失败，继续尝试下一个块
        }
        // 如果没找到，先尝试2*2切割找
        int blockWidth4 = bufferedImage.getWidth() / 2; // 将图片分为4列
        int blockHeight4 = bufferedImage.getHeight() / 2; // 将图片分为4行
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                try {
                    // 截取图片块
                    BufferedImage subImage = bufferedImage.getSubimage(
                            j * blockWidth4, i * blockHeight4, blockWidth4, blockHeight4);
                    LuminanceSource subSource = new BufferedImageLuminanceSource(subImage);
                    BinaryBitmap subBitmap = new BinaryBitmap(new HybridBinarizer(subSource));
                    Result subResult = new MultiFormatReader().decode(subBitmap);
                    if (subResult.getBarcodeFormat() == BarcodeFormat.EAN_13) {
                        return subResult.getText();
                    }
                } catch (NotFoundException ignored) {
                    // 忽略单个块的识别失败，继续尝试下一个块
                }
            }
        }
        // 如果2*2切割仍未找到，再尝试3*3切割找
        int blockWidth3 = bufferedImage.getWidth() / 3; // 将图片分为3列
        int blockHeight3 = bufferedImage.getHeight() / 3; // 将图片分为3行
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                try {
                    // 截取图片块
                    BufferedImage subImage = bufferedImage.getSubimage(
                            j * blockWidth3, i * blockHeight3, blockWidth3, blockHeight3);
                    LuminanceSource subSource = new BufferedImageLuminanceSource(subImage);
                    BinaryBitmap subBitmap = new BinaryBitmap(new HybridBinarizer(subSource));
                    Result subResult = new MultiFormatReader().decode(subBitmap);
                    if (subResult.getBarcodeFormat() == BarcodeFormat.EAN_13) {
                        return subResult.getText();
                    }
                } catch (NotFoundException ignored) {
                    // 忽略单个块的识别失败，继续尝试下一个块
                }
            }
        }
        // 如果3*3切割仍未找到，返回未能识别到条形码
        throw new ServiceException("未能识别到条形码");
    }

    /**
     * 从图片文件读取ISBN条形码内容
     *
     * @param imageFile 图片文件
     * @return ISBN条形码内容
     * @throws IOException       如果图片读取失败
     * @throws NotFoundException 如果未找到条形码
     */
    public static String readISBNFromImage(File imageFile) throws IOException, NotFoundException {
        BufferedImage bufferedImage = ImageIO.read(imageFile);
        LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result = new MultiFormatReader().decode(bitmap);
        return result.getText();
    }
}
